@file:UseSerializers(ResourceLocationSerializer::class, ItemStackSerializer::class, TextAsJsonStringSerializer::class)
@file:OptIn(ExperimentalSerializationApi::class)

package com.lalameow.researchstation.api.technology

import com.lalameow.researchstation.MOD_PREFIX
import com.lalameow.researchstation.ResearchStation
import com.lalameow.researchstation.translatable
import com.lalameow.researchstation.util.serialization.TextAsJsonStringSerializer
import kotlinx.serialization.Contextual
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import net.minecraft.text.TranslatableText
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.silkmc.silk.core.serialization.serializers.ResourceLocationSerializer
import net.silkmc.silk.nbt.serialization.serializer.ItemStackSerializer
import kotlin.math.max

/**
 * 科技
 */
@Serializable
data class Technology(
    val id: Identifier,
    val icon: Set<ItemStack>,
    /**
     * [Can't use wildcard](https://github.com/Kotlin/kotlinx.serialization/issues/607)
     */
    val requirements: Set<TechnologyRequirement<out @Contextual Any?>>,
    val rewards: Set<TechnologyReward>,
    val criteria: Set<TechnologyCriterion>,
    // 未解锁时是否可见
    val visible: Boolean = true,
    val name: Text = ResearchStation.translatable("technology.$id"),
    val description: Text? = null
)

fun Set<TechnologyRequirement<*>>.progressing() =
    mapTo(mutableSetOf()) { it.progressing() }

@Serializable
data class TechnologyCategory(
    val id: Identifier,
    val icon: Set<ItemStack>,
    val technologies: Set<Technology>,
    /**
     * 绘制时使用的背景路径
     */
    val background: Identifier? = DEFAULT_BACKGROUND,
    val name: Text = ResearchStation.translatable("category.$id"),
    val description: Text? = null
) {
    companion object {
        val DEFAULT_BACKGROUND =
            Identifier.tryParse("textures/gui/advancements/backgrounds/adventure.png")
    }
}

interface TechnologyRequirement<Type> {
    val resource: TechnologyResource<Type>

    /**
     * @return 返回超出资源
     */
    fun test(resource: TechnologyResource<Type>) = this.resource.let {
        if (resource.test(it.type)) {
            construct(
                resource.type,
                max(0L, it.count - resource.count)
            )
        } else resource
    }

    fun progressing(): Progressing<Type>
    fun construct(type: Type, count: Long): TechnologyResource<Type> {
        throw UnsupportedOperationException()
    }

    interface Progressing<Type> : TechnologyRequirement<Type> {
        var current: Long
        fun complete() = current >= resource.count
    }
}

interface TechnologyCriterion {
    val name: Text

    /**
     * @param player 玩家
     * @return 如果失败返回 [Text]
     */
    fun test(player: ServerPlayerEntity): Text?

    companion object {
        /**
         * 不满足前置时的提示
         */
        val LOCKING: Text = TranslatableText(ResearchStation.MOD_PREFIX + ".criterion.locking")
    }
}

interface TechnologyResource<T> {
    /**
     * 当前资源数量
     */
    val count: Long
    val name: Text
    val type: T

    /**
     * 测试输入是否为期望资源
     */
    fun test(input: T): Boolean
}

interface TechnologyReward {
    val name: Text

    /**
     * @param world 世界
     * @param pos 位置
     * @param player 玩家
     */
    operator fun get(world: World, pos: BlockPos, player: PlayerEntity)
}
